import os
import sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, 
                            QComboBox, QSpinBox, QFrame, QFileDialog, QMessageBox,
                            QTableWidget, QTableWidgetItem, QHeaderView, QSplitter,
                            QGroupBox, QRadioButton, QButtonGroup, QFormLayout,
                            QScrollArea, QSizePolicy)
from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtGui import QColor, QIcon

class SPCControlChart:
    """SPC控制图基类，提供基本方法"""
    
    @staticmethod
    def validate_data(df, required_columns):
        """验证数据的有效性"""
        for col in required_columns:
            if not pd.to_numeric(df[col], errors='coerce').notnull().all():
                raise ValueError(f"'{col}'列包含非数值数据")
        
        # 移除所有空值行
        if df[required_columns].isnull().any().any():
            original_len = len(df)
            df = df.dropna(subset=required_columns)
            if len(df) < original_len:
                print(f"警告：删除了{original_len - len(df)}行含有空值的数据")
        
        # 检查数据范围
        for col in required_columns:
            if len(df[col]) == 0:
                raise ValueError(f"'{col}'列没有有效数据")
        
        return df

class ShewartChart(SPCControlChart):
    """休哈特控制图"""
    
    @staticmethod
    def calculate_control_limits(data):
        """计算控制限"""
        try:
            mean = data.mean()
            std = data.std()
            UCL = mean + 3 * std
            LCL = mean - 3 * std
            
            return {
                'data': data,
                'mean': mean,
                'UCL': UCL,
                'LCL': LCL,
                'std': std
            }
        except Exception as e:
            raise ValueError(f"计算控制限时出错: {str(e)}")
    
    # 不同子组大小对应的控制限系数
    CONSTANTS = {
        2: {'A2': 1.880, 'D3': 0, 'D4': 3.267, 'A3': 2.659, 'B3': 0, 'B4': 3.267, 'C4': 0.7979},
        3: {'A2': 1.023, 'D3': 0, 'D4': 2.575, 'A3': 1.954, 'B3': 0, 'B4': 2.568, 'C4': 0.8862},
        4: {'A2': 0.729, 'D3': 0, 'D4': 2.282, 'A3': 1.628, 'B3': 0, 'B4': 2.266, 'C4': 0.9213},
        5: {'A2': 0.577, 'D3': 0, 'D4': 2.114, 'A3': 1.427, 'B3': 0, 'B4': 2.089, 'C4': 0.9400},
        6: {'A2': 0.483, 'D3': 0, 'D4': 2.004, 'A3': 1.287, 'B3': 0.030, 'B4': 1.970, 'C4': 0.9515},
        7: {'A2': 0.419, 'D3': 0.076, 'D4': 1.924, 'A3': 1.182, 'B3': 0.118, 'B4': 1.882, 'C4': 0.9594},
        8: {'A2': 0.373, 'D3': 0.136, 'D4': 1.864, 'A3': 1.099, 'B3': 0.185, 'B4': 1.815, 'C4': 0.9650},
        9: {'A2': 0.337, 'D3': 0.184, 'D4': 1.816, 'A3': 1.032, 'B3': 0.239, 'B4': 1.761, 'C4': 0.9693},
        10: {'A2': 0.308, 'D3': 0.223, 'D4': 1.777, 'A3': 0.975, 'B3': 0.284, 'B4': 1.716, 'C4': 0.9727},
    }
    
    @staticmethod
    def process_data(data, subgroup_size=5):
        """处理数据，分组并计算基本统计量"""
        if not isinstance(data, pd.Series):
            data = pd.Series(data)
        
        # 处理缺失值和无限值
        data = data.replace([np.inf, -np.inf], np.nan)
        
        # 使用前向填充处理缺失值
        data = data.ffill()
        
        # 如果仍有缺失值（例如，序列开头的NaN），使用均值填充
        if data.isna().any():
            data = data.fillna(data.mean())
        
        # 确保数据长度足够
        if len(data) < subgroup_size:
            raise ValueError(f"数据点不足，无法生成控制图。需要至少{subgroup_size}个数据点。")
        
        n = len(data)
        num_subgroups = n // subgroup_size
        
        # 如果数据点不能被子组大小整除，舍弃多余的数据点
        data = data[:num_subgroups * subgroup_size]
        
        # 将数据重塑为二维数组，每行为一个子组
        reshaped_data = data.values.reshape(num_subgroups, subgroup_size)
        
        return reshaped_data, num_subgroups

class XbarRChart(SPCControlChart):
    """X bar-R 控制图 (均值-极差控制图)"""
    
    @staticmethod
    def calculate_control_limits(data, subgroup_size=5):
        """计算X-bar和R控制图的控制限"""
        try:
            reshaped_data, _ = ShewartChart.process_data(data, subgroup_size)
            
            # 计算X-bar（子组均值）和R（极差）
            x_bar = np.mean(reshaped_data, axis=1)
            r = np.ptp(reshaped_data, axis=1)  # peak to peak (max - min)
            
            # 检查数据变异性
            if np.all(r < 1e-10):
                raise ValueError("数据几乎没有变异性，无法创建有意义的控制图。")
            
            # 计算总体均值和平均极差
            x_bar_mean = np.mean(x_bar)
            r_mean = np.mean(r)
            
            # 根据子组大小获取控制图系数
            constants = ShewartChart.CONSTANTS.get(subgroup_size, ShewartChart.CONSTANTS[5])
            A2, D3, D4 = constants['A2'], constants['D3'], constants['D4']
            
            # 计算控制限
            UCL_x_bar = x_bar_mean + A2 * r_mean
            LCL_x_bar = x_bar_mean - A2 * r_mean
            UCL_r = D4 * r_mean
            LCL_r = D3 * r_mean
            
            return {
                'x_bar': x_bar,
                'r': r,
                'x_bar_mean': x_bar_mean,
                'r_mean': r_mean,
                'UCL_x_bar': UCL_x_bar,
                'LCL_x_bar': LCL_x_bar,
                'UCL_r': UCL_r,
                'LCL_r': LCL_r
            }
        except Exception as e:
            raise ValueError(f"计算控制限时出错: {str(e)}")

class XbarSChart(SPCControlChart):
    """X bar-S 控制图 (均值-标准差控制图)"""
    
    @staticmethod
    def calculate_control_limits(data, subgroup_size=5):
        """计算X-bar和S控制图的控制限"""
        try:
            reshaped_data, _ = ShewartChart.process_data(data, subgroup_size)
            
            # 计算X-bar（子组均值）和S（标准差）
            x_bar = np.mean(reshaped_data, axis=1)
            s = np.std(reshaped_data, axis=1, ddof=1)  # 样本标准差
            
            # 检查数据变异性
            if np.all(s < 1e-10):
                raise ValueError("数据几乎没有变异性，无法创建有意义的控制图。")
            
            # 计算总体均值和平均标准差
            x_bar_mean = np.mean(x_bar)
            s_mean = np.mean(s)
            
            # 根据子组大小获取控制图系数
            constants = ShewartChart.CONSTANTS.get(subgroup_size, ShewartChart.CONSTANTS[5])
            A3, B3, B4 = constants['A3'], constants['B3'], constants['B4']
            
            # 计算控制限
            UCL_x_bar = x_bar_mean + A3 * s_mean
            LCL_x_bar = x_bar_mean - A3 * s_mean
            UCL_s = B4 * s_mean
            LCL_s = B3 * s_mean
            
            return {
                'x_bar': x_bar,
                's': s,
                'x_bar_mean': x_bar_mean,
                's_mean': s_mean,
                'UCL_x_bar': UCL_x_bar,
                'LCL_x_bar': LCL_x_bar,
                'UCL_s': UCL_s,
                'LCL_s': LCL_s
            }
        except Exception as e:
            raise ValueError(f"计算控制限时出错: {str(e)}")

class SPCWidget(QWidget):
    """SPC功能的主界面部件"""
    
    def __init__(self, parent=None, main_window=None):
        super().__init__(parent)
        self.main_window = main_window  # 保存对主窗口的引用
        self.data_df = None  # 存储数据
        self.file_path = None  # 存储文件路径
        self.charts = []  # 存储图表对象
        self.current_chart_type = "Xbar-R"  # 默认图表类型
        self.subgroup_size = 5  # 默认子组大小
        
        # 设置UI
        self.setup_ui()
        
        # 初始化完成后自动加载质检数据
        try:
            self.load_data()
            
            # 设置默认选择的参数
            if self.data_df is not None and self.parameter_combo.count() > 0:
                # 优先选择"质检L"参数
                if '质检L' in self.data_df.columns:
                    index = self.parameter_combo.findText('质检L')
                    if index >= 0:
                        self.parameter_combo.setCurrentIndex(index)
                # 如果没有"质检L"，则选择第一个参数
                elif self.parameter_combo.count() > 0:
                    self.parameter_combo.setCurrentIndex(0)
        except Exception as e:
            print(f"初始化加载数据失败: {str(e)}")
    
    def setup_ui(self):
        """设置UI布局"""
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(15)
        
        # 创建顶部控制区域 - 使用卡片式设计
        control_frame = QFrame()
        control_frame.setStyleSheet("""
            QFrame {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                          stop:0 #ffffff, stop:1 #f7f7f7);
                border-radius: 12px;
                margin: 10px;
            }
        """)
        
        control_layout = QHBoxLayout(control_frame)
        control_layout.setContentsMargins(25, 25, 25, 25)
        control_layout.setSpacing(30)
        
        # === 创建左侧参数区域 ===
        params_container = QWidget()
        params_layout = QVBoxLayout(params_container)
        params_layout.setContentsMargins(0, 0, 0, 0)
        params_layout.setSpacing(20)
        
        # 参数设置标题
        params_title = QLabel("参数设置")
        params_title.setStyleSheet("""
            font-size: 18px;
            font-weight: bold;
            color: #1890ff;
            margin-bottom: 8px;
            padding-bottom: 5px;
            border-bottom: 1px solid #f0f0f0;
        """)
        params_layout.addWidget(params_title)
        
        # 子组大小区域
        size_container = QWidget()
        size_layout = QHBoxLayout(size_container)
        size_layout.setContentsMargins(0, 0, 0, 0)
        size_layout.setSpacing(15)
        
        size_label = QLabel("子组大小:")
        size_label.setStyleSheet("""
            font-size: 15px;
            color: #262626;
            min-width: 80px;
            font-weight: 500;
        """)
        size_layout.addWidget(size_label)
        
        self.subgroup_size_spinner = QSpinBox()
        self.subgroup_size_spinner.setMinimum(2)
        self.subgroup_size_spinner.setMaximum(10)
        self.subgroup_size_spinner.setValue(5)
        self.subgroup_size_spinner.setFixedWidth(100)
        self.subgroup_size_spinner.setFixedHeight(32)
        self.subgroup_size_spinner.setStyleSheet("""
            QSpinBox {
                border: 1px solid #d9d9d9;
                border-radius: 4px;
                padding: 4px 8px;
                background-color: white;
                font-size: 14px;
            }
            QSpinBox:hover {
                border-color: #40a9ff;
            }
            QSpinBox:focus {
                border-color: #1890ff;
            }
            QSpinBox::up-button, QSpinBox::down-button {
                border: none;
                width: 20px;
                height: 14px;
                background-color: transparent;
            }
            QSpinBox::up-button:hover, QSpinBox::down-button:hover {
                background-color: #e6f7ff;
            }
            QSpinBox::up-arrow {
                width: 0;
                height: 0;
                border-left: 4px solid transparent;
                border-right: 4px solid transparent;
                border-bottom: 6px solid #595959;
                margin-top: 2px;
            }
            QSpinBox::down-arrow {
                width: 0;
                height: 0;
                border-left: 4px solid transparent;
                border-right: 4px solid transparent;
                border-top: 6px solid #595959;
                margin-bottom: 2px;
            }
        """)
        size_layout.addWidget(self.subgroup_size_spinner)
        size_layout.addStretch()
        
        # 监测特性区域
        param_container = QWidget()
        param_layout = QHBoxLayout(param_container)
        param_layout.setContentsMargins(0, 0, 0, 0)
        param_layout.setSpacing(15)
        
        param_label = QLabel("监测特性:")
        param_label.setStyleSheet("""
            font-size: 15px;
            color: #262626;
            min-width: 80px;
            font-weight: 500;
        """)
        param_layout.addWidget(param_label)
        
        self.parameter_combo = QComboBox()
        self.parameter_combo.setEnabled(False)  # 初始禁用，直到数据加载
        self.parameter_combo.setFixedHeight(32)
        self.parameter_combo.setMinimumWidth(200)
        self.parameter_combo.setStyleSheet("""
            QComboBox {
                border: 1px solid #d9d9d9;
                border-radius: 4px;
                padding: 4px 30px 4px 10px;
                background-color: white;
                font-size: 14px;
                min-width: 200px;
            }
            QComboBox:hover {
                border-color: #40a9ff;
            }
            QComboBox:focus, QComboBox:open {
                border-color: #1890ff;
            }
            QComboBox::drop-down {
                subcontrol-origin: padding;
                subcontrol-position: right center;
                width: 25px;
                border-left: none;
            }
            QComboBox::down-arrow {
                width: 0;
                height: 0;
                border-left: 4px solid transparent;
                border-right: 4px solid transparent;
                border-top: 6px solid #595959;
                margin-top: 2px;
            }
            QComboBox QAbstractItemView {
                border: 1px solid #d9d9d9;
                border-radius: 0px 0px 4px 4px;
                background-color: white;
                selection-background-color: #e6f7ff;
                selection-color: #1890ff;
                outline: none;
            }
            QComboBox:disabled {
                background-color: #f5f5f5;
                color: #bfbfbf;
                border-color: #d9d9d9;
            }
        """)
        param_layout.addWidget(self.parameter_combo)
        
        # 添加子组件到参数布局
        params_layout.addWidget(size_container)
        params_layout.addWidget(param_container)
        params_layout.addStretch()
        
        # === 创建右侧操作区域 ===
        actions_container = QWidget()
        actions_layout = QVBoxLayout(actions_container)
        actions_layout.setContentsMargins(0, 0, 0, 0)
        actions_layout.setSpacing(20)
        
        # 操作区标题
        actions_title = QLabel("操作")
        actions_title.setStyleSheet("""
            font-size: 18px;
            font-weight: bold;
            color: #1890ff;
            margin-bottom: 8px;
            padding-bottom: 5px;
            border-bottom: 1px solid #f0f0f0;
        """)
        actions_layout.addWidget(actions_title)
        
        # 加载数据按钮
        self.load_data_btn = QPushButton(" 加载数据")  # 空格用于在图标后添加间距
        self.load_data_btn.setFixedHeight(40)
        self.load_data_btn.setMinimumWidth(140)
        self.load_data_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        self.load_data_btn.setVisible(False)  # 设置按钮不可见
        
        # 设置按钮图标
        data_icon = QIcon()
        # 这里假设有一个图标文件，如果没有，图标不会显示，但不会报错
        if os.path.exists("icons/data.png"):
            data_icon = QIcon("icons/data.png")
        self.load_data_btn.setIcon(data_icon)
        
        self.load_data_btn.setStyleSheet("""
            QPushButton {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                          stop:0 #e6f7ff, stop:1 #bae7ff);
                color: #0050b3;
                border: 1px solid #91d5ff;
                border-radius: 8px;
                padding: 8px 16px;
                font-size: 15px;
                font-weight: bold;
                text-align: center;
            }
            QPushButton:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                          stop:0 #bae7ff, stop:1 #91d5ff);
                border-color: #1890ff;
            }
            QPushButton:pressed {
                background: #1890ff;
                color: white;
                border-color: #096dd9;
            }
        """)
        
        # 生成控制图按钮
        self.generate_chart_btn = QPushButton(" 生成控制图")  # 空格用于在图标后添加间距
        self.generate_chart_btn.setEnabled(False)  # 初始禁用，直到数据加载
        self.generate_chart_btn.setFixedHeight(40)
        self.generate_chart_btn.setMinimumWidth(140)
        self.generate_chart_btn.setCursor(Qt.CursorShape.PointingHandCursor)

        
        # 设置按钮图标
        chart_icon = QIcon()
        if os.path.exists("icons/chart.png"):
            chart_icon = QIcon("icons/chart.png")
        self.generate_chart_btn.setIcon(chart_icon)
        
        self.generate_chart_btn.setStyleSheet("""
            QPushButton {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                          stop:0 #f6ffed, stop:1 #d9f7be);
                color: #135200;
                border: 1px solid #b7eb8f;
                border-radius: 8px;
                padding: 8px 16px;
                font-size: 15px;
                font-weight: bold;
                text-align: center;
            }
            QPushButton:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                          stop:0 #d9f7be, stop:1 #b7eb8f);
                border-color: #52c41a;
            }
            QPushButton:pressed {
                background: #52c41a;
                color: white;
                border-color: #389e0d;
            }
            QPushButton:disabled {
                background: #f5f5f5;
                color: #d9d9d9;
                border-color: #d9d9d9;
            }
        """)
        
        actions_layout.addWidget(self.load_data_btn)
        actions_layout.addWidget(self.generate_chart_btn)
        actions_layout.addStretch()
        
        # 添加两个主要区域到控制布局
        control_layout.addWidget(params_container, 2)  # 参数区域占2
        control_layout.addWidget(actions_container, 1)  # 操作区域占1
        
        # 将控制框架添加到主布局
        main_layout.addWidget(control_frame)
        
        # 创建并添加图表显示区域
        self.chart_area = QWidget()
        chart_area_layout = QVBoxLayout(self.chart_area)
        chart_area_layout.setContentsMargins(5, 5, 5, 5)
        
        # 为图表区域创建一个卡片式背景
        chart_card = QFrame()
        chart_card.setStyleSheet("""
            QFrame {
                background-color: white;
                border-radius: 12px;
                border: 1px solid #e8e8e8;
            }
        """)
        
        self.chart_layout = QVBoxLayout(chart_card)
        self.chart_layout.setContentsMargins(20, 20, 20, 20)
        
        # 设置初始未加载数据的提示
        self.no_data_label = QLabel("请加载数据或从主窗口选择控制图类型")
        self.no_data_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.no_data_label.setStyleSheet("""
            font-size: 16px; 
            color: #8c8c8c; 
            padding: 50px;
            font-weight: 500;
        """)
        self.chart_layout.addWidget(self.no_data_label)
        
        chart_area_layout.addWidget(chart_card)
        
        # 添加图表区域到主布局
        main_layout.addWidget(self.chart_area)
        
        # 绑定事件
        self.load_data_btn.clicked.connect(self.load_data)
        self.generate_chart_btn.clicked.connect(self.generate_chart)
        self.subgroup_size_spinner.valueChanged.connect(self.on_subgroup_size_changed)
    
    def load_data(self):
        """加载数据文件"""
        try:
            # 直接使用"质检数据.xlsx"作为数据源
            file_path = "data\质检数据.xlsx"
            
            # 读取Excel文件
            self.data_df = pd.read_excel(file_path)
            
            # 确保所有列都是数值类型
            for column in self.data_df.columns:
                try:
                    self.data_df[column] = pd.to_numeric(self.data_df[column], errors='coerce')
                except:
                    pass
            
            # 删除包含NaN的行
            original_len = len(self.data_df)
            self.data_df = self.data_df.dropna()
            if len(self.data_df) < original_len:
                print(f"警告：删除了{original_len - len(self.data_df)}行含有空值的数据")
            
            self.file_path = file_path
            self.update_parameter_combo()
            
            # 只有在成功加载数据后才启用生成图表按钮
            if len(self.data_df) > 0:
                self.generate_chart_btn.setEnabled(True)
            else:
                self.generate_chart_btn.setEnabled(False)
                QMessageBox.warning(self, "警告", "数据文件中没有有效数据!")
                
        except Exception as e:
            QMessageBox.critical(self, "错误", f"加载质检数据时出错: {str(e)}")
            import traceback
            traceback.print_exc()
            
            # 如果加载失败，尝试让用户手动选择文件
            file_path, _ = QFileDialog.getOpenFileName(
                self, "选择数据文件", "", "Excel文件 (*.xlsx *.xls);;CSV文件 (*.csv);;所有文件 (*)"
            )
            
            if file_path:
                try:
                    if file_path.endswith('.csv'):
                        self.data_df = pd.read_csv(file_path)
                    else:
                        self.data_df = pd.read_excel(file_path)
                    
                    # 确保所有列都是数值类型
                    for column in self.data_df.columns:
                        try:
                            self.data_df[column] = pd.to_numeric(self.data_df[column], errors='coerce')
                        except:
                            pass
                    
                    # 删除包含NaN的行
                    original_len = len(self.data_df)
                    self.data_df = self.data_df.dropna()
                    if len(self.data_df) < original_len:
                        print(f"警告：删除了{original_len - len(self.data_df)}行含有空值的数据")
                    
                    self.file_path = file_path
                    self.update_parameter_combo()
                    
                    # 只有在成功加载数据后才启用生成图表按钮
                    if len(self.data_df) > 0:
                        self.generate_chart_btn.setEnabled(True)
                    else:
                        self.generate_chart_btn.setEnabled(False)
                        QMessageBox.warning(self, "警告", "数据文件中没有有效数据!")
                    
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"加载数据时出错: {str(e)}")
                    import traceback
                    traceback.print_exc()
    
    def update_parameter_combo(self):
        """更新特性选择下拉框"""
        if self.data_df is not None:
            # 清除当前项
            self.parameter_combo.clear()
            
            # 打印数据框的列名，用于调试
            print("数据框的列名:", list(self.data_df.columns))
            
            # 尝试将所有列转换为数值类型
            for column in self.data_df.columns:
                try:
                    self.data_df[column] = pd.to_numeric(self.data_df[column], errors='coerce')
                except Exception as e:
                    print(f"转换列 '{column}' 时出错: {str(e)}")
            
            # 只添加数值类型的列
            numeric_columns = self.data_df.select_dtypes(include=[np.number]).columns.tolist()
            print("数值类型的列:", numeric_columns)
            
            if numeric_columns:
                self.parameter_combo.addItems(numeric_columns)
                self.parameter_combo.setEnabled(True)
                
                # 默认选择第一个质检参数
                if '质检L' in numeric_columns:
                    self.parameter_combo.setCurrentText('质检L')
                    print("已选择'质检L'参数")
                elif len(numeric_columns) > 0:
                    self.parameter_combo.setCurrentText(numeric_columns[0])
                    print(f"已选择'{numeric_columns[0]}'参数")
            else:
                QMessageBox.warning(self, "警告", "数据文件中没有数值类型的列!")
                self.parameter_combo.setEnabled(False)
                self.generate_chart_btn.setEnabled(False)
    
    def on_subgroup_size_changed(self, value):
        """当子组大小改变时调用"""
        self.subgroup_size = value
    
    def clear_charts(self):
        """清除当前显示的所有图表"""
        # 清除布局中的所有控件
        while self.chart_layout.count():
            item = self.chart_layout.takeAt(0)
            widget = item.widget()
            if widget:
                widget.deleteLater()
        
        # 清除图表列表
        self.charts = []
    
    def generate_chart(self):
        """生成并显示控制图"""
        if self.data_df is None:
            QMessageBox.warning(self, "警告", "请先加载数据!")
            return
            
        if self.parameter_combo.currentText() == "":
            QMessageBox.warning(self, "警告", "请选择监测特性!")
            return
        
        # 清除当前图表
        self.clear_charts()
        
        # 获取选定的特性
        parameter = self.parameter_combo.currentText()
        print(f"选择的参数: '{parameter}'")
        print(f"数据框的列: {list(self.data_df.columns)}")
        
        try:
            # 检查参数是否在数据框中
            if parameter not in self.data_df.columns:
                QMessageBox.critical(self, "错误", f"数据中不存在'{parameter}'列!")
                return
                
            # 确保数据是数值类型
            data = pd.to_numeric(self.data_df[parameter], errors='coerce')
            print(f"数据类型: {type(data)}, 数据长度: {len(data)}")
            
            # 处理缺失值
            if data.isna().any():
                original_count = len(data)
                data = data.dropna()
                if len(data) < original_count:
                    QMessageBox.warning(
                        self, 
                        "警告", 
                        f"'{parameter}'列中有{original_count - len(data)}个缺失值已被移除。"
                    )
            
            # 检查数据是否足够
            if len(data) < self.subgroup_size:
                QMessageBox.critical(
                    self, 
                    "错误", 
                    f"数据点不足，无法生成控制图。需要至少{self.subgroup_size}个数据点。"
                )
                return
                
            print(f"数据前5个值: {data.head()}")
            
            # 根据所选图表类型生成控制图
            if self.current_chart_type == "Xbar-R":
                self.generate_xbar_r_chart(data, parameter)
            elif self.current_chart_type == "Xbar-S":
                self.generate_xbar_s_chart(data, parameter)
            elif self.current_chart_type == "Shewhart":
                self.generate_shewhart_chart(data, parameter)
            elif self.current_chart_type == "Individuals":
                # 这里可以实现个体值-移动极差图
                QMessageBox.information(self, "信息", "个体值-移动极差图功能待实现")
            elif self.current_chart_type == "CUSUM":
                # 这里可以实现累积和控制图
                QMessageBox.information(self, "信息", "累积和控制图功能待实现")
            elif self.current_chart_type == "EWMA":
                # 这里可以实现指数加权移动平均图
                QMessageBox.information(self, "信息", "指数加权移动平均图功能待实现")
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"生成控制图时出错: {str(e)}")
            import traceback
            traceback.print_exc()
    
    def generate_xbar_r_chart(self, data, parameter):
        """生成X-bar和R控制图"""
        try:
            # 计算控制限
            results = XbarRChart.calculate_control_limits(data, self.subgroup_size)
            
            # 创建X-bar控制图
            fig_xbar = Figure(figsize=(8, 4))
            ax_xbar = fig_xbar.add_subplot(111)
            
            # 绘制X-bar控制图
            ax_xbar.plot(results['x_bar'], marker='o', linestyle='-', color='blue')
            ax_xbar.axhline(results['UCL_x_bar'], color='red', linestyle='--', label='UCL')
            ax_xbar.axhline(results['x_bar_mean'], color='green', linestyle='-', label='CL')
            ax_xbar.axhline(results['LCL_x_bar'], color='red', linestyle='--', label='LCL')
            
            # 添加标签
            ax_xbar.set_title(f"{parameter}的X-bar控制图")
            ax_xbar.set_xlabel("子组")
            ax_xbar.set_ylabel("子组均值")
            ax_xbar.legend()
            
            # 添加控制限值文本
            ax_xbar.text(len(results['x_bar'])-1, results['UCL_x_bar'], 
                         f'UCL: {results["UCL_x_bar"]:.3f}', 
                         color='red', va='bottom')
            ax_xbar.text(len(results['x_bar'])-1, results['x_bar_mean'], 
                         f'CL: {results["x_bar_mean"]:.3f}', 
                         color='green', va='bottom')
            ax_xbar.text(len(results['x_bar'])-1, results['LCL_x_bar'], 
                         f'LCL: {results["LCL_x_bar"]:.3f}', 
                         color='red', va='top')
            
            # 创建X-bar图表的画布
            canvas_xbar = FigureCanvas(fig_xbar)
            
            # 创建R控制图
            fig_r = Figure(figsize=(8, 4))
            ax_r = fig_r.add_subplot(111)
            
            # 绘制R控制图
            ax_r.plot(results['r'], marker='o', linestyle='-', color='blue')
            ax_r.axhline(results['UCL_r'], color='red', linestyle='--', label='UCL')
            ax_r.axhline(results['r_mean'], color='green', linestyle='-', label='CL')
            ax_r.axhline(results['LCL_r'], color='red', linestyle='--', label='LCL')
            
            # 添加标签
            ax_r.set_title(f"{parameter}的R控制图")
            ax_r.set_xlabel("子组")
            ax_r.set_ylabel("极差")
            ax_r.legend()
            
            # 添加控制限值文本
            ax_r.text(len(results['r'])-1, results['UCL_r'], 
                      f'UCL: {results["UCL_r"]:.3f}', 
                      color='red', va='bottom')
            ax_r.text(len(results['r'])-1, results['r_mean'], 
                      f'CL: {results["r_mean"]:.3f}', 
                      color='green', va='bottom')
            ax_r.text(len(results['r'])-1, results['LCL_r'], 
                      f'LCL: {results["LCL_r"]:.3f}', 
                      color='red', va='top')
            
            # 创建R图表的画布
            canvas_r = FigureCanvas(fig_r)
            
            # 添加画布到布局
            self.chart_layout.addWidget(canvas_xbar)
            self.chart_layout.addWidget(canvas_r)
            
            # 保存图表对象以防止垃圾回收
            self.charts.append(canvas_xbar)
            self.charts.append(canvas_r)
            
            # 设置紧凑布局
            fig_xbar.tight_layout()
            fig_r.tight_layout()
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"生成X-bar和R控制图时出错: {str(e)}")
    
    def generate_xbar_s_chart(self, data, parameter):
        """生成X-bar和S控制图"""
        try:
            # 计算控制限
            results = XbarSChart.calculate_control_limits(data, self.subgroup_size)
            
            # 创建X-bar控制图
            fig_xbar = Figure(figsize=(8, 4))
            ax_xbar = fig_xbar.add_subplot(111)
            
            # 绘制X-bar控制图
            ax_xbar.plot(results['x_bar'], marker='o', linestyle='-', color='blue')
            ax_xbar.axhline(results['UCL_x_bar'], color='red', linestyle='--', label='UCL')
            ax_xbar.axhline(results['x_bar_mean'], color='green', linestyle='-', label='CL')
            ax_xbar.axhline(results['LCL_x_bar'], color='red', linestyle='--', label='LCL')
            
            # 添加标签
            ax_xbar.set_title(f"{parameter}的X-bar控制图")
            ax_xbar.set_xlabel("子组")
            ax_xbar.set_ylabel("子组均值")
            ax_xbar.legend()
            
            # 添加控制限值文本
            ax_xbar.text(len(results['x_bar'])-1, results['UCL_x_bar'], 
                         f'UCL: {results["UCL_x_bar"]:.3f}', 
                         color='red', va='bottom')
            ax_xbar.text(len(results['x_bar'])-1, results['x_bar_mean'], 
                         f'CL: {results["x_bar_mean"]:.3f}', 
                         color='green', va='bottom')
            ax_xbar.text(len(results['x_bar'])-1, results['LCL_x_bar'], 
                         f'LCL: {results["LCL_x_bar"]:.3f}', 
                         color='red', va='top')
            
            # 创建X-bar图表的画布
            canvas_xbar = FigureCanvas(fig_xbar)
            
            # 创建S控制图
            fig_s = Figure(figsize=(8, 4))
            ax_s = fig_s.add_subplot(111)
            
            # 绘制S控制图
            ax_s.plot(results['s'], marker='o', linestyle='-', color='blue')
            ax_s.axhline(results['UCL_s'], color='red', linestyle='--', label='UCL')
            ax_s.axhline(results['s_mean'], color='green', linestyle='-', label='CL')
            ax_s.axhline(results['LCL_s'], color='red', linestyle='--', label='LCL')
            
            # 添加标签
            ax_s.set_title(f"{parameter}的S控制图")
            ax_s.set_xlabel("子组")
            ax_s.set_ylabel("标准差")
            ax_s.legend()
            
            # 添加控制限值文本
            ax_s.text(len(results['s'])-1, results['UCL_s'], 
                      f'UCL: {results["UCL_s"]:.3f}', 
                      color='red', va='bottom')
            ax_s.text(len(results['s'])-1, results['s_mean'], 
                      f'CL: {results["s_mean"]:.3f}', 
                      color='green', va='bottom')
            ax_s.text(len(results['s'])-1, results['LCL_s'], 
                      f'LCL: {results["LCL_s"]:.3f}', 
                      color='red', va='top')
            
            # 创建S图表的画布
            canvas_s = FigureCanvas(fig_s)
            
            # 添加画布到布局
            self.chart_layout.addWidget(canvas_xbar)
            self.chart_layout.addWidget(canvas_s)
            
            # 保存图表对象以防止垃圾回收
            self.charts.append(canvas_xbar)
            self.charts.append(canvas_s)
            
            # 设置紧凑布局
            fig_xbar.tight_layout()
            fig_s.tight_layout()
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"生成X-bar和S控制图时出错: {str(e)}")
    
    # 为不同类型的控制图添加方法
    def show_Xbar_R(self):
        """显示X-bar R控制图"""
        self.current_chart_type = "Xbar-R"
        if self.data_df is not None and self.parameter_combo.currentText():
            self.generate_chart()
    
    def show_Xbar_S(self):
        """显示X-bar S控制图"""
        self.current_chart_type = "Xbar-S"
        if self.data_df is not None and self.parameter_combo.currentText():
            self.generate_chart()
    
    def show_Individuals(self):
        """显示个体值-移动极差图"""
        self.current_chart_type = "Individuals"
        if self.data_df is not None and self.parameter_combo.currentText():
            self.generate_chart()
    
    def show_CUSUM(self):
        """显示累积和控制图"""
        self.current_chart_type = "CUSUM"
        if self.data_df is not None and self.parameter_combo.currentText():
            self.generate_chart()
    
    def show_EWMA(self):
        """显示指数加权移动平均图"""
        self.current_chart_type = "EWMA"
        if self.data_df is not None and self.parameter_combo.currentText():
            self.generate_chart()
            
    def show_Shewhart(self):
        """显示休哈特控制图"""
        self.current_chart_type = "Shewhart"
        if self.data_df is not None and self.parameter_combo.currentText():
            self.generate_chart()
            
    def generate_shewhart_chart(self, data, parameter):
        """生成休哈特控制图"""
        try:
            # 计算控制限
            results = ShewartChart.calculate_control_limits(data)
            
            # 创建控制图
            fig = Figure(figsize=(10, 6))
            ax = fig.add_subplot(111)
            
            # 绘制数据线和点
            x_values = range(1, len(data) + 1)
            ax.plot(x_values, data,
                   marker='o',
                   markersize=4,
                   linestyle='-',
                   linewidth=1.5,
                   color='blue',
                   label='观测值',
                   zorder=3)
            
            # 绘制控制限
            ax.axhline(results['mean'], color='green', linestyle='-', label=f'中心线 (CL={results["mean"]:.3f})', zorder=2)
            ax.axhline(results['UCL'], color='red', linestyle='--', label=f'上控制限 (UCL={results["UCL"]:.3f})', zorder=2)
            ax.axhline(results['LCL'], color='red', linestyle='--', label=f'下控制限 (LCL={results["LCL"]:.3f})', zorder=2)
            
            # 标记超出控制限的点
            out_of_control = data[(data > results['UCL']) | (data < results['LCL'])]
            if not out_of_control.empty:
                out_indices = out_of_control.index
                ax.scatter([data.index.get_loc(idx) + 1 for idx in out_indices],
                         out_of_control,
                         color='red',
                         s=50,
                         zorder=5,
                         label='超出控制限点')
            
            # 添加统计信息
            stats_text = (f'样本数：{len(data)}\n'
                         f'平均值：{results["mean"]:.3f}\n'
                         f'标准差：{results["std"]:.3f}\n'
                         f'UCL：{results["UCL"]:.3f}\n'
                         f'LCL：{results["LCL"]:.3f}')
            ax.text(0.02, 0.98, stats_text,
                   transform=ax.transAxes,
                   verticalalignment='top',
                   bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
            
            # 设置图表属性
            ax.set_title(f'休哈特控制图 - {parameter}')
            ax.set_xlabel('样本序号')
            ax.set_ylabel(f'{parameter}值')
            ax.grid(True, linestyle=':', alpha=0.6, zorder=1)
            # 调整图例位置和布局，避免重叠
            ax.legend(
                loc='upper center',
                bbox_to_anchor=(0.5, -0.15),
                ncol=3,
                frameon=True,
                fancybox=True,
                shadow=True
            )
            # 调整图表底部边距，为外部图例留出空间
            fig.subplots_adjust(bottom=0.2)
            
            # 创建画布
            canvas = FigureCanvas(fig)
            self.chart_layout.addWidget(canvas)
            self.charts.append(canvas)
            
            # 设置紧凑布局
            fig.tight_layout()
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"生成休哈特控制图时出错: {str(e)}")